package top.wilsonlv.jaguar.cloud.auth.extension.face;


import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.StringUtils;
import top.wilsonlv.jaguar.cloud.auth.sdk.enums.PrincipalType;
import top.wilsonlv.jaguar.cloud.auth.sdk.token.FaceAuthenticationToken;
import top.wilsonlv.jaguar.cloud.auth.security.LoginFailureHandler;
import top.wilsonlv.jaguar.cloud.auth.security.LoginSuccessHandler;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;

import static top.wilsonlv.jaguar.cloud.auth.extension.OAuth2ExtensionContant.*;

/**
 * @author lvws
 * @since 2022/1/6
 */
@Slf4j
public class FaceAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    public static final String FACE_LOGIN_PATH = "/login/face";

    public FaceAuthenticationFilter(AuthenticationManager authenticationManager,
                                    LoginSuccessHandler loginSuccessHandler, LoginFailureHandler loginFailureHandler) {
        super(new AntPathRequestMatcher(FACE_LOGIN_PATH, HttpMethod.POST.name()), authenticationManager);

        setAuthenticationSuccessHandler(loginSuccessHandler);
        setAuthenticationFailureHandler(loginFailureHandler);
    }

    @SneakyThrows
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (!request.getMethod().equals(HttpMethod.POST.name())) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }

        String username = request.getParameter(QUERY_PARAMETER_USERNAME_KEY);
        String deviceUid = request.getParameter(QUERY_PARAMETER_DEVICE_UID_KEY);

        if (!StringUtils.hasText(username) && !StringUtils.hasText(deviceUid)) {
            throw new BadCredentialsException("设备ID与用户名不可同时为空");
        }

        String face;
        try (ServletInputStream inputStream = request.getInputStream();
             ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            IOUtils.copy(inputStream, outputStream);
            face = outputStream.toString();
        }

        if (!StringUtils.hasText(face)) {
            throw new BadCredentialsException("人脸信息为非空");
        }

        if (face.startsWith(DATA_IMAGE_PNG_BASE64)) {
            face = face.substring(DATA_IMAGE_PNG_BASE64.length());
        }

        FaceAuthenticationToken token;
        if (StringUtils.hasText(username)) {
            token = new FaceAuthenticationToken(username, face, PrincipalType.USERNAME);
        } else {
            token = new FaceAuthenticationToken(deviceUid, face, PrincipalType.DEVICE_ID);
        }

        token.setDetails(this.authenticationDetailsSource.buildDetails(request));
        return this.getAuthenticationManager().authenticate(token);
    }

}
